/**********************************************************************************
 * 文件名称：main.c
 * 功能说明：主函数初始化
 * 作者：laud（qq：554163925）
 * 修改记录：
 * 1、ucos时钟节拍OS_CPU_SysTickHandler，由系统systick产生。
 *    可通过SysTick_Config(SystemCoreClock / 1000)进行重置，目前使用1ms节拍
 **********************************************************************************/
#include "includes.h"
#include <string.h>

/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/ 
static  OS_TCB   AppTaskStartTCB;
static  CPU_STK  AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];

static  OS_TCB   AppTaskMsgProTCB;
static  CPU_STK  AppTaskMsgProStk[APP_CFG_TASK_MsgPro_STK_SIZE];

static  OS_TCB   AppTaskCom1ProTCB;
static  CPU_STK  AppTaskCom1ProStk[APP_CFG_TASK_Com1Pro_STK_SIZE];

static  OS_TCB   AppTaskCom2ProTCB;
static  CPU_STK  AppTaskCom2ProStk[APP_CFG_TASK_Com2Pro_STK_SIZE];


/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/
static  OS_SEM       GsmRcvSemp;	/* 用于printf互斥 */


/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static  void  	AppTaskStart    (void *p_arg);
static 	void 	AppTaskMsgPro(void *p_arg);
static 	void 	AppTaskCom1Pro(void *p_arg);
static 	void 	AppTaskCom2Pro(void *p_arg);

	
static  void  AppTaskCreate         (void);
void  AppObjCreate			(void);
void GSM_Task_IfInit		(void);


/* 主函数入口 */
int main(void)
{ 		
	OS_ERR  err;  
	
	/* 初始化uC/OS-III 内核 */
	OSInit(&err);  

	/* 创建一个启动任务（也就是主任务）。启动任务会创建所有的应用程序任务 */
	OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,  /* 任务控制块地址 */           
                 (CPU_CHAR     *)"App Task Start",  /* 任务名 */
                 (OS_TASK_PTR   )AppTaskStart,      /* 启动任务函数地址 */
                 (void         *)0,                 /* 传递给任务的参数 */
                 (OS_PRIO       )APP_CFG_TASK_START_PRIO, /* 任务优先级 */
                 (CPU_STK      *)&AppTaskStartStk[0],     /* 堆栈基地址 */
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE / 10, /* 堆栈监测区，这里表示后10%作为监测区 */
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,      /* 堆栈空间大小 */
                 (OS_MSG_QTY    )0,  /* 本任务支持接受的最大消息数 */
                 (OS_TICK       )0,  /* 设置时间片 */
                 (void         *)0,  /* 堆栈空间大小 */  
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
		
				 /*  定义如下：
					OS_OPT_TASK_STK_CHK      使能检测任务栈，统计任务栈已用的和未用的
					OS_OPT_TASK_STK_CLR      在创建任务时，清零任务栈
					OS_OPT_TASK_SAVE_FP      如果CPU有浮点寄存器，则在任务切换时保存浮点寄存器的内容
				 */  
                 (OS_ERR       *)&err);

	/* 启动多任务系统，控制权交给uC/OS-III */
	OSStart(&err);                                               

	(void)&err;

	return (0);
}




/*
*********************************************************************************************************
*	函 数 名: AppTaskStart
*	功能说明: 这是一个启动任务，在多任务系统启动后，必须初始化滴答计数器。本任务主要实现按键和触摸检测。
*	形    参: p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
	优 先 级: 2
*********************************************************************************************************
*/
static tmr_t *tmrRealTimeSender = NULL;
static void led_toggle(uint8_t ID);

static void led_toggle(uint8_t ID)
{
	printf("\r\n.usr_tmr_ok");
}
		 	

static  void  AppTaskStart (void *p_arg)
{
	OS_ERR      err;
	
	/* 仅用于避免编译器告警，编译器不会产生任何目标代码 */	
	(void)p_arg;  
	
	/* BSP 初始化。 BSP = Board Support Package 板级支持包，可以理解为底层驱动。*/
	CPU_Init();  /* 此函数要优先调用，因为外设驱动中使用的us和ms延迟是基于此函数的 */	
	bsp_Init(); 
  
	GSMxx_IfInit();


	if(NULL == tmrRealTimeSender ){
 			tmrRealTimeSender = TMR_Subscribe(false,100,TMR_TYPE_100MS,(tmr_procTriggerHdlr_t)led_toggle);
    }

#if OS_CFG_STAT_TASK_EN > 0u
     OSStatTaskCPUUsageInit(&err);   
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
    CPU_IntDisMeasMaxCurReset();
#endif
		
//	USART_Start(DEV_GSM,(usart_procDataHdlr_f ) MODEM_ReadData );

	/* 创建应用程序的任务 */
	AppTaskCreate();

	/* 创建任务通信 */
	AppObjCreate();
	
//	GSM_Task_IfInit();
	gsm_Init();
//	GSM_ModemOpen(0);
	while(1)
	{
		LED1=~LED1;
		OSTimeDly(1000, OS_OPT_TIME_DLY, &err);
	}     
}


/*
*********************************************************************************************************
*	函 数 名: AppTaskCreate
*	功能说明: 创建应用任务
*	形    参：p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
*********************************************************************************************************
*/
static  void  AppTaskCreate (void)
{
	OS_ERR      err;
	
	//创建MsgPro任务
	OSTaskCreate((OS_TCB       *)&AppTaskMsgProTCB,             
                 (CPU_CHAR     *)"App Task MspPro",
                 (OS_TASK_PTR   )AppTaskMsgPro, 
                 (void         *)0,
                 (OS_PRIO       )APP_CFG_TASK_MsgPro_PRIO,
                 (CPU_STK      *)&AppTaskMsgProStk[0],
                 (CPU_STK_SIZE  )APP_CFG_TASK_MsgPro_STK_SIZE / 10,
                 (CPU_STK_SIZE  )APP_CFG_TASK_MsgPro_STK_SIZE,
                 (OS_MSG_QTY    )0,
                 (OS_TICK       )0,
                 (void         *)0,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);
	//uart1接收并转发任务
	OSTaskCreate((OS_TCB       *)&AppTaskCom1ProTCB,             
                 (CPU_CHAR     *)"App Task Com1Pro",
                 (OS_TASK_PTR   )AppTaskCom1Pro, 
                 (void         *)0,
                 (OS_PRIO       )APP_CFG_TASK_Com1Pro_PRIO,
                 (CPU_STK      *)&AppTaskCom1ProStk[0],
                 (CPU_STK_SIZE  )APP_CFG_TASK_Com1Pro_STK_SIZE / 10,
                 (CPU_STK_SIZE  )APP_CFG_TASK_Com1Pro_STK_SIZE,
                 (OS_MSG_QTY    )0,
                 (OS_TICK       )0,
                 (void         *)0,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);		
	//uart2接收转发任务
	OSTaskCreate((OS_TCB       *)&AppTaskCom2ProTCB,             
                 (CPU_CHAR     *)"App Task Com2Pro",
                 (OS_TASK_PTR   )AppTaskCom2Pro, 
                 (void         *)0,
                 (OS_PRIO       )APP_CFG_TASK_Com2Pro_PRIO,
                 (CPU_STK      *)&AppTaskCom2ProStk[0],
                 (CPU_STK_SIZE  )APP_CFG_TASK_Com2Pro_STK_SIZE / 10,
                 (CPU_STK_SIZE  )APP_CFG_TASK_Com2Pro_STK_SIZE,
                 (OS_MSG_QTY    )0,
                 (OS_TICK       )0,
                 (void         *)0,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);		
}


/*
*********************************************************************************************************
*	函 数 名: AppObjCreate
*	功能说明: 创建任务通讯
*	形    参: p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
*********************************************************************************************************
*/
void  AppObjCreate (void)
{
	OS_ERR err;
	
    /* 创建信号量数值为1的时候可以实现互斥功能，也就是只有一个资源可以使用 
	   本例程是将串口1的打印函数作为保护的资源。防止串口打印的时候被其它任务抢占
	   造成串口打印错乱。*/
	OSSemCreate((OS_SEM    *)&GsmRcvSemp,
				(CPU_CHAR  *)"GsmRcvSemp",
				(OS_SEM_CTR )1,
				(OS_ERR    *)&err);
}


/*
*********************************************************************************************************
*	函 数 名: AppTaskMsgPro
*	功能说明: 暂未使用
*	形    参: p_arg 是在创建该任务时传递的形参
*	返 回 值: 无
	优 先 级: 3
*********************************************************************************************************
*/
static void AppTaskMsgPro(void *p_arg)
{
	char pMsg[20] = "\r\n.sys_run";

	OS_ERR	err;

	(void)p_arg;

	while(1)
	{	
		comSendBuf(COM1,(uint8_t*)pMsg,strlen(pMsg));					
		OSTimeDly(3000, OS_OPT_TIME_DLY, &err);
	}   
}


/*
*********************************************************************************************************
*	函 数 名: 
*	功能说明: 串口1收到数据，立刻在GSM串口2上输出
*	形     参: 
*	返 回 值: 
	优 先 级: 
*********************************************************************************************************
*/
static void AppTaskCom1Pro(void *p_arg)
{
	uint8_t ucData;

	OS_ERR      err;

	(void)p_arg;

	while(1)
	{	
		if (comGetChar(COM1, &ucData))
		{
			comSendBuf(COM2,&ucData,1); 		
			continue;						
		}		
		OSTimeDly(100, OS_OPT_TIME_DLY, &err);
	}   
}


/*
*********************************************************************************************************
*	函 数 名: 
*	功能说明: GSM串口2收到数据时，立刻在串口1上输出
*	形     参:
*	返 回 值:
	优 先 级:
*********************************************************************************************************
*/
static void AppTaskCom2Pro(void *p_arg)
{
	uint8_t ucData;

	OS_ERR      err;

	(void)p_arg;

	while(1)
	{	
		if (comGetChar(COM2, &ucData))
		{
			comSendBuf(COM1,&ucData,1); 		
//			OSGsmRcvDataPro_SemPost();			
			continue;						
		}		
		OSTimeDly(100, OS_OPT_TIME_DLY, &err);
	}   
}




void GsmRcvDataProc(void)
{
//	LED1=~LED1;
}


void GSM_Task_IfInit(void)
{
	OS_ERR     err;

	while(1)
	{	
		/* 请求信号量 */
		OSSemPend((OS_SEM *)&GsmRcvSemp,
				(OS_TICK )0,						/* 这里是等待时间 */
				(OS_OPT  )OS_OPT_PEND_BLOCKING,		/* OS_OPT_PEND_BLOCKING：	 信号量无效时，任务挂起等待信号量， 
													   OS_OPT_PEND_NON_BLOCKING：信号量无效时，任务直接返回。	*/
				(CPU_TS*  )0,						
				(OS_ERR *)&err);
		GsmRcvDataProc();
	} 

}

/* 释放&发送信号量 */
/* 如果没有任务在等待该信号量的话则OSSemPost()函数只是简单的将信号量加1，
   然后返回到调用该函数的任务中继续运行。如果有一个或者多个任务在等待这个信
   号量，则优先级最高的任务将获得这个信号量，然后由调度器来判定刚获得信号量
   的任务是否为系统中优先级最高的就绪任务，如果是，则系统将进行任务切换，
   运行这个就绪任务，
   
 * 貌似还可以使用这个函数，直接调用任务快
 * OSTaskSemPend(OS_TICK timeout, OS_OPT opt, CPU_TS * p_ts, OS_ERR * p_err)
 */
void  OSGsmRcvDataPro_SemPost (void)
{
		OS_ERR     err;
		OSSemPost((OS_SEM *)&GsmRcvSemp,
		(OS_OPT  )OS_OPT_POST_1,			/*opt：用来选择信号量发送的方式。
  											OS_OPT_POST_1：仅向等待该信号量的优先级最高的任务发送信号量；
  											OS_OPT_POST_ALL：向等待该信号量的所有任务发送信号量；
  											OS_OPT_POST_NO_SCHED：该选项禁止在本函数内执行任务调度操作。
  											即使该函数使得更高优先级的任务结束挂起进入就绪状态，
  											也不会执行任务调度，而是会在其他后续函数中完成任务调度 */
		(OS_ERR *)&err);
}



